package define

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
)

// RsaEncryptWithSha1AndBase64 RSA1 私钥加签
func RsaEncryptWithSha1AndBase64(privateKeyStr, content string) (encrypted string, err error) {
	return RSAWithShaAndBase64(crypto.SHA1, privateKeyStr, content)
}

// RsaVerifyWithSha1AndBase64 RSA 公钥验签
func RsaVerifyWithSha1AndBase64(publicKeyStr, content, sign string) error {
	return RSAVerifyWithShaAndBase64(crypto.SHA1, publicKeyStr, content, sign)
}

// RsaEncryptWithSha256AndBase64 RSA256 私钥加签
func RsaEncryptWithSha256AndBase64(privateKeyStr, content string) (encrypted string, err error) {
	return RSAWithShaAndBase64(crypto.SHA256, privateKeyStr, content)
}

// RsaVerifyWithSha256AndBase64 RSA256 公钥验签
func RsaVerifyWithSha256AndBase64(publicKeyStr, content, sign string) error {
	return RSAVerifyWithShaAndBase64(crypto.SHA256, publicKeyStr, content, sign)
}

// RsaEncryptWithSha512AndBase64 RSA512 私钥加签
func RsaEncryptWithSha512AndBase64(privateKeyStr, content string) (encrypted string, err error) {
	return RSAWithShaAndBase64(crypto.SHA512, privateKeyStr, content)
}

// RsaVerifyWithSha512AndBase64 RSA512 公钥验签
func RsaVerifyWithSha512AndBase64(publicKeyStr, content, sign string) error {
	return RSAVerifyWithShaAndBase64(crypto.SHA512, publicKeyStr, content, sign)
}

// RSAWithShaAndBase64 RSA 私钥加签
func RSAWithShaAndBase64(cryptoHash crypto.Hash, privateKeyStr, content string) (sign string, err error) {
	// 获取私钥
	privateKey, err := StringToRsaPrivateKey(privateKeyStr)
	if err != nil {
		return
	}

	// 获取哈希值
	hashBytes, err := HashBytes(cryptoHash, content)
	if err != nil {
		return
	}

	// 获取签名
	signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, cryptoHash, hashBytes)
	if err != nil {
		return
	}

	// base64编码
	sign = base64.StdEncoding.EncodeToString(signature)

	return
}

// RSAVerifyWithShaAndBase64 RSA 公钥验签
func RSAVerifyWithShaAndBase64(cryptoHash crypto.Hash, publicKeyStr, content, sign string) (err error) {
	// 获取公钥
	rsaPublicKey, err := StringToRsaPublicKey(publicKeyStr)
	if err != nil {
		return err
	}

	// 获取哈希值
	hashBytes, err := HashBytes(cryptoHash, content)
	if err != nil {
		return
	}

	// base64解码
	signByte, err := base64.StdEncoding.DecodeString(sign)
	if err != nil {
		return err
	}

	return rsa.VerifyPKCS1v15(rsaPublicKey, cryptoHash, hashBytes, signByte)
}

func HashBytes(cryptoHash crypto.Hash, content string, append ...[]byte) (hashBytes []byte, err error) {
	hash := cryptoHash.New()
	_, err = hash.Write([]byte(content))

	if err != nil {
		return
	}

	if append == nil || len(append) == 0 {
		hashBytes = hash.Sum(nil)
	} else {
		hashBytes = hash.Sum(append[0])
	}

	return
}

// CreatePkcs8Keys 创建密钥对
func CreatePkcs8Keys(keyLength int) (privateKey string, publicKey string, err error) {
	rsaPrivateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
	if err != nil {
		return
	}

	privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(rsaPrivateKey)
	if err != nil {
		return
	}

	privateKey = string(pem.EncodeToMemory(
		&pem.Block{
			Type:  "PRIVATE KEY",
			Bytes: privateKeyBytes,
		},
	))

	publicKeyBytes, err := x509.MarshalPKIXPublicKey(&rsaPrivateKey.PublicKey)
	if err != nil {
		return
	}

	publicKey = string(pem.EncodeToMemory(
		&pem.Block{
			Type:  "PUBLIC KEY",
			Bytes: publicKeyBytes,
		},
	))

	return
}

// StringToRsaPrivateKey 字符串转结构体
// -----BEGIN PRIVATE KEY-----
// MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANjPlda1LwoNXTdw
// BUtyRnWASIWnXD0ALjeOIoOFwFOlly/vK+7IiEmHzx4xqf1DN4yPzIfamz0EG46S
// XwIEs9/pJOtzeiwlebgWnZeP0zSr+GnGHucBca83TqIuu6aIy4OfMa3kHL0dRipf
// u9taPxzJzRYubaEHunkhAnUXB14hAgMBAAECgYAbDtUhZZ1IQOC4UXenscxPT8I9
// Q+TEDCi4cDmodmHJTqoupkeyVj6EBrn3h7UyUVg2Z5/b+JFVLRUPVv8abmHQPf81
// HEBDC9If0IQyXKf4xA0+AUS1kQuRQ3qT1qCvrsLgyiuiSctEOxIqZrwylNyBxtxs
// 6MCNpoK+UUtx1pKAQQJBAP187erc+BvBBD6LpACbLbKrgDR/xVvQ/3ZEG4SvuCy9
// rqmj3U5H5Ol/ilLl9Q/QerorMCxrTby9mrohpQ/UkCQQDa9Zw1aGw34heTdf0s
// TSwwOynnrGBZEIK2X3ah5GvTcYfdmvoQdotk5M8AgDVR2Ln11NYyGV3/2cyryYiG
// U5IZAkEAiRSzUOx4XAHweqZnZVCF0PZ/2WQzZWjLjbhdLU8diUyijp2qFb/4ZPm5
// o2QohLE2dJxz2tyoeovWXHs9qX+cyQJARZb8D6lhg51S+uXsEhFw8t9K4TvS31u0
// /3t1u9xaPLh/gvoHcgYLJYTnGXSl/Z5Q9AWyEfgn/PHe79Y8ktyquQJBAJG9+oe+
// 356ERO1J3NQ9uzk1r+c2cIjct6EvmT3jGo/bbcV/2p3n/Oe41uw0dLtS0tQs+C/1
// xQPdRu3Mh+h2wpo=
// -----END PRIVATE KEY-----
func StringToRsaPrivateKey(privateKeyStr string) (rsaPrivateKey *rsa.PrivateKey, err error) {
	block, _ := pem.Decode([]byte(privateKeyStr))
	if block == nil {
		err = errors.New("private key pem decode error")
		return
	}

	privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return
	}

	rsaPrivateKey, ok := privateKey.(*rsa.PrivateKey)
	if !ok {
		err = errors.New("privateKey not *rsa.PrivateKey")
	}

	return
}

// StringToRsaPublicKey 字符串转结构体
// -----BEGIN PUBLIC KEY-----
// MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYz5XWtS8KDV03cAVLckZ1gEiF
// p1w9AC43jiKDhcBTpZcv7yvuyIhJh88eMan9QzeMj8yH2ps9BBuOkl8CBLPf6STr
// c3osJXm4Fp2Xj9M0q/hpxh7nAXGvN06iLrumiMuDnzGt5By9HUYqX7vbWj8cyc0W
// Lm2hB7p5IQJ1FwdeIQIDAQAB
// -----END PUBLIC KEY-----
func StringToRsaPublicKey(publicKey string) (rsaPublicKey *rsa.PublicKey, err error) {
	block, _ := pem.Decode([]byte(publicKey))
	if block == nil {
		err = errors.New("public key pem decode error")
		return
	}

	key, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return
	}

	rsaPublicKey = key.(*rsa.PublicKey)

	return
}
